package com.presto.directo.utils

import android.Manifest
import android.annotation.SuppressLint
import android.app.ActivityManager
import android.content.*
import android.content.Context.BATTERY_SERVICE
import android.content.pm.PackageManager
import android.net.*
import android.net.wifi.WifiManager
import android.os.*
import android.provider.*
import android.telephony.TelephonyManager
import android.text.format.Formatter
import androidx.core.app.ActivityCompat
import androidx.fragment.app.FragmentActivity
import com.tbruyelle.rxpermissions3.RxPermissions
import java.io.*
import java.util.*


@SuppressLint("MissingPermission", "HardwareIds")
class DeviceInfoUtil(private val activity: FragmentActivity) {

    fun getDevice(): TreeMap<String, Any?> {
        val map = TreeMap<String, Any?>()
        //系统
        map["system_version"] = Build.VERSION.SDK_INT
        map["imei"] = getImei()
        map["currentSystemTime"] = System.currentTimeMillis()
        map["uptimemillis"] = SystemClock.uptimeMillis()
        map["androidId"] = getAndroidId()
        map["gaId"] = SPUtil.get("gaId", "")
        map["osVersion"] = Build.VERSION.RELEASE
        map["root"] = isRoot()
        map["developer_options"] = Settings.Secure.getInt(activity.contentResolver, Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) > 0
        map["isusbdebug"] = Settings.Secure.getInt(activity.contentResolver, Settings.Global.ADB_ENABLED, 0) > 0
        map["uuid"] = UUID.randomUUID().toString()
        map["device_name"] = getTryValue { Settings.Secure.getString(activity.contentResolver, "bluetooth_name") }
        //硬件
        map["displayResolution"] = getScreenWidth().toString() + "x" + getScreenHeight().toString()
        map["cpu_type"] = Build.HARDWARE
        map["manufacturer"] = Build.BRAND
        map["model"] = Build.MODEL
        map["board"] = Build.BOARD
        map["cpuCount"] = getNumberOfCPUCores()
        map["isSimulator"] = false
        map["cpuSpeed"] = getMaxCpuFreq()
        map["deviceArch"] = getTryValue { Build.SUPPORTED_ABIS[0] }
        //电池
        map["batterymax"] = getBatteryMax()
        map["device_electricity"] = getBattery()
        map["batterylevel"] = getBattery()
        val batteryInfo = getBatteryInfo()
        map["ischarging"] = batteryInfo.ischarging
        map["isaccharge"] = batteryInfo.isaccharge
        map["isusbcharge"] = batteryInfo.isusbcharge
        map["screen_brighness"] = getScreenBrightness()
        //内存
        map["main_storage"] = getTryValue { Environment.getExternalStorageDirectory().path }
        map["external_storage"] = getTryValue { Environment.getExternalStorageDirectory().path }
        map["totalMemory"] = getTotalMemory()
        map["ram_usable_size"] = getAvailMemory()
        map["totalStorage"] = getDataTotalSize()
        map["memory_card_size_usa"] = getSDAvailableSize()
        activity.runOnUiThread {
            map["audio_external"] = getMediaCount(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI)
            map["audio_internal"] = getMediaCount(MediaStore.Audio.Media.INTERNAL_CONTENT_URI)
            map["video_external"] = getMediaCount(MediaStore.Video.Media.EXTERNAL_CONTENT_URI)
            map["video_internal"] = getMediaCount(MediaStore.Video.Media.INTERNAL_CONTENT_URI)
            map["images_external"] = getMediaCount(MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
            map["images_internal"] = getMediaCount(MediaStore.Images.Media.INTERNAL_CONTENT_URI)
            map["picCount"] = getMediaCount(MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
            map["download_files"] = getDownLoadCount()
        }
        map["appTotalMemory"] = Runtime.getRuntime().totalMemory()
        map["appMaxmemory"] = Runtime.getRuntime().maxMemory()
        map["appFreememory"] = Runtime.getRuntime().freeMemory()
        //网络
        val ip: String = SPUtil.get("ipAddress", "")
        map["ipAddress"] = ip
        map["netip"] = if (isWifiConnected() == "WIFI") "" else ip
        map["wifiip"] = if (isWifiConnected() == "WIFI") ip else ""
        map["wifiName"] = getWifiName()
        map["networkType"] = isWifiConnected()
        map["macAddress"] = WifiUtil.newMac
        val networkOperator = getTelephonyManager()?.networkOperator ?: ""
        map["network_operator"] = networkOperator
        map["network_operator_name"] = getTelephonyManager()?.networkOperatorName ?: ""
        map["sim_country_iso"] = getTelephonyManager()?.simCountryIso ?: ""
        map["mcc"] = getTryValue { networkOperator.substring(0, 3) }
        map["mnc"] = getTryValue { networkOperator.substring(3) }
        //地区语言
        map["country"] = "co"
        map["time_zone_id"] = TimeZone.getDefault().id
        val locale = activity.resources.configuration.locale
        map["locale_iso_3_language"] = locale.isO3Language
        map["locale_iso_3_country"] = locale.isO3Country
        map["locale_display_language"] = locale.displayLanguage
        return map
    }

    fun getMaxCpuFreq(): String {
        var result = ""
        val cmd: ProcessBuilder
        try {
            val args = arrayOf(
                "/system/bin/cat",
                "/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq"
            )
            cmd = ProcessBuilder(*args)
            val process = cmd.start()
            val `in`: InputStream = process.inputStream
            val re = ByteArray(24)
            while (`in`.read(re) != -1) {
                result += String(re)
            }
            `in`.close()
        } catch (ex: IOException) {
            ex.printStackTrace()
            result = "N/A"
        }
        return ((result.trim { it <= ' ' }.toDoubleOrNull() ?: 0.0) / 1000).toString() + " MHz"
    }

    fun getImei(): String? {
        return getTryValue {
            if (!hasReadPhonePermission()) {
                ""
            } else {
                (activity.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager).deviceId ?: ""
            }
        }
    }

    fun getAndroidId(): String? {
        return getTryValue {
            Settings.System.getString(activity.contentResolver, Settings.Secure.ANDROID_ID)
        }
    }

    private fun getWifiName(): String {
        var wifiName = ""
        return getTryValue {
            val wifiManager = activity.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager
            wifiManager.connectionInfo?.let {
                wifiName = it.ssid?.replace("\"", "") ?: ""
            }
            if (wifiName == "<unknown ssid>") {
                wifiName = ""
            }
            wifiName
        }
    }

    private fun isRoot(): Boolean {
        return try {
            return File("/system/bin/su").exists()
                    || File("/system/xbin/su").exists()
                    || File("/system/sbin/su").exists()
                    || File("/sbin/su").exists()
                    || File("/vendor/bin/su").exists()
        } catch (e: Exception) {
            false
        }
    }

    private fun getBattery(): String {
        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            getTryValue {
                val batteryManager = activity.getSystemService(BATTERY_SERVICE) as BatteryManager
                batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY).toString()
            }
        } else {
            ""
        }
    }

    private fun getBatteryMax(): String {
        val POWER_PROFILE_CLASS = "com.android.internal.os.PowerProfile"
        return getTryValue {
            val mPowerProfile = Class.forName(POWER_PROFILE_CLASS).getConstructor(Context::class.java).newInstance(activity)
            val batteryCapacity = Class.forName(POWER_PROFILE_CLASS).getMethod("getBatteryCapacity").invoke(mPowerProfile) as Double
            batteryCapacity.toString()
        }
    }

    data class BatteryInfo(
        val ischarging: Boolean = false,
        val isaccharge: Boolean = false,
        val isusbcharge: Boolean = false
    )

    private fun getBatteryInfo(): BatteryInfo {
        return try {
            val filter = IntentFilter(Intent.ACTION_BATTERY_CHANGED)
            val intent = activity.registerReceiver(null, filter)
            val ischarging = intent?.getIntExtra("status", 0) != BatteryManager.BATTERY_STATUS_NOT_CHARGING
            val isaccharge = intent?.getIntExtra("plugged", 0) == BatteryManager.BATTERY_PLUGGED_AC
            val isusbcharge = intent?.getIntExtra("plugged", 0) == BatteryManager.BATTERY_PLUGGED_USB
            BatteryInfo(ischarging, isaccharge, isusbcharge)
        } catch (e: Exception) {
            BatteryInfo(false, false, false)
        }
    }

    private fun getScreenBrightness(): String {
        return getTryValue {
            Settings.System.getInt(activity.contentResolver, Settings.System.SCREEN_BRIGHTNESS).toString()
        }
    }

    private fun getTotalMemory(): String {
        return getTryValue {
            val am = activity.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
            val mi = ActivityManager.MemoryInfo()
            am.getMemoryInfo(mi)
            (mi.availMem / 1000000).toInt().toString() + " MB"
        }
    }

    private fun getAvailMemory(): String {
        return getTryValue {
            val am = activity.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
            val mi = ActivityManager.MemoryInfo()
            am.getMemoryInfo(mi)
            Formatter.formatFileSize(activity, mi.availMem) ?: ""
        }
    }

    private fun getDataTotalSize(): String {
        return getTryValue {
            val path: File? = activity.getExternalFilesDir(null)
            val stat = StatFs(path?.path)
            val blockSize = stat.blockSizeLong
            val totalBlocks = stat.blockCountLong
            (blockSize * totalBlocks / 1000000).toInt().toString() + " MB"
        }
    }

    private fun getSDAvailableSize(): String? {
        return getTryValue {
            val path: File? = activity.getExternalFilesDir(null)
            val stat = StatFs(path?.path)
            val blockSize = stat.blockSizeLong
            val availableBlocks = stat.availableBlocksLong
            Formatter.formatFileSize(activity, blockSize * availableBlocks) ?: ""
        }
    }

    private fun getNumberOfCPUCores(): Int {
        return try {
            File("/sys/devices/system/cpu/").listFiles(CPU_FILTER).size
        } catch (e: Exception) {
            0
        }
    }

    private fun isWifiConnected(): String {
        val connectivityManager = activity.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager?
        if (connectivityManager != null) {
            val networkInfo = connectivityManager.activeNetworkInfo
            if (networkInfo != null) {
                return networkInfo.typeName
            }
        }
        return ""
    }

    private fun hasReadPhonePermission(): Boolean {
        return ActivityCompat.checkSelfPermission(activity, Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED
    }

    private val CPU_FILTER = FileFilter {
        val path = it.name
        if (path.startsWith("cpu")) {
            for (i in 3 until path.length) {
                if (path[i] < '0' || path[i] > '9') {
                    return@FileFilter false
                }
            }
            return@FileFilter true
        }
        return@FileFilter false
    }

    fun saveLog() {
        try {
            val dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS)
            if (!dir.exists()) {
                dir.mkdirs()
            }
            val logFile = File(dir.path, "log.txt")
            if (!logFile.exists()) {
                logFile.createNewFile()
            }
        } catch (e: Exception) {
        }
    }

    fun hasLog(): Boolean {
        return try {
            val dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS)
            val logFile = File(dir.path, "log.txt")
            logFile.exists()
        } catch (e: Exception) {
            false
        }
    }

    private fun getMediaCount(uri: Uri): Int {
        if (!RxPermissions(activity).isGranted(Manifest.permission.READ_EXTERNAL_STORAGE)) {
            return 0
        }
        return try {
            val cursor = activity.contentResolver.query(uri, null, null, null, null)
            return cursor?.count ?: 0
        } catch (e: Exception) {
            e.toString().logger()
            0
        }
    }

    private fun getDownLoadCount(): Int {
        if (!RxPermissions(activity).isGranted(Manifest.permission.READ_EXTERNAL_STORAGE)) {
            return 0
        }
        val args = arrayOf(Environment.getExternalStorageDirectory().path + File.separator + Environment.DIRECTORY_DOWNLOADS + "%")
        return try {
            val cursor = activity.contentResolver.query(MediaStore.Files.getContentUri("external"), null, "_data like ?", args, null)
            return cursor?.count ?: 0
        } catch (e: Exception) {
            e.toString().logger()
            0
        }
    }

    private fun getTelephonyManager(): TelephonyManager? {
        return try {
            val telephonyManager = activity.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
            telephonyManager
        } catch (e: Exception) {
            null
        }
    }

    private fun getTryValue(block: () -> String): String {
        return try {
            block()
        } catch (e: Exception) {
            ""
        }
    }
}